package cn.schoolwow.workflow.module.instance.action.service;

import cn.schoolwow.quickdao.domain.DAO;
import cn.schoolwow.quickdao.domain.database.dql.condition.Condition;
import cn.schoolwow.quickdao.domain.transaction.Transaction;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;
import cn.schoolwow.util.domain.query.instanceList.QueryInstanceList;
import cn.schoolwow.workflow.domain.deploy.WorkFlowDefinitionOption;
import cn.schoolwow.workflow.domain.instance.WorkFlowInstanceStatus;
import cn.schoolwow.workflow.entity.WorkFlowDefinition;
import cn.schoolwow.workflow.entity.WorkFlowInstance;
import cn.schoolwow.workflow.entity.WorkFlowTask;
import cn.schoolwow.workflow.module.common.flow.AddWorkFlowHistoryFlow;
import cn.schoolwow.workflow.module.instance.action.flow.start.ExecuteAfterInstanceFinishListenerFlow;
import cn.schoolwow.workflow.module.instance.query.flow.GetWorkFlowInstanceConditionFlow;

import java.util.List;

public class RevokeWorkFlowInstanceServiceFlow implements BusinessFlow {
    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        flowContext.executeFlowList(new GetWorkFlowInstanceConditionFlow());
        setWorkFlowInstanceList(flowContext);
        checkAllowRevoke(flowContext);
        transactionUpdate(flowContext);
        flowContext.executeFlowList(new ExecuteAfterInstanceFinishListenerFlow());
    }

    @Override
    public String name() {
        return "撤销工作流实例服务流程";
    }

    private void setWorkFlowInstanceList(FlowContext flowContext){
        Condition condition = flowContext.checkInstanceData(Condition.class);
        DAO dao = flowContext.checkInstanceData(DAO.class);

        dao.addRecordString("查询需要撤销的工作流实例");

        List<WorkFlowInstance> workFlowInstanceList = condition.execute().getList();
        if(workFlowInstanceList.isEmpty()){
            flowContext.broken("工作流实例查询为空");
        }
        flowContext.putTemporaryData("workFlowInstanceList", workFlowInstanceList);

        List<Long> workFlowInstanceIdList = QueryInstanceList.newQuery(workFlowInstanceList)
                .execute()
                .getSingleFieldValueList("id");
        flowContext.putCurrentFlowData("workFlowInstanceIdList", workFlowInstanceIdList);
    }

    private void checkAllowRevoke(FlowContext flowContext){
        List<Long> workFlowInstanceIdList = flowContext.checkData("workFlowInstanceIdList", List.class);
        DAO dao = flowContext.checkInstanceData(DAO.class);

        dao.addRecordString("判断流程定义选项是否允许撤销实例");
        List<Long> definitionIdList = dao.query(WorkFlowInstance.class)
                .addInQuery("id", workFlowInstanceIdList)
                .addColumn("definitionId")
                .execute()
                .getSingleColumnList(Long.class);
        List<WorkFlowDefinition> workFlowDefinitionList = dao.query(WorkFlowDefinition.class)
                .addInQuery("id", definitionIdList)
                .addColumn("name")
                .addColumn("option")
                .execute()
                .getList();
        for(WorkFlowDefinition workFlowDefinition:workFlowDefinitionList){
            if(null==workFlowDefinition.getOption()){
                continue;
            }
            WorkFlowDefinitionOption workFlowDefinitionOption = workFlowDefinition.getOption().toJavaObject(WorkFlowDefinitionOption.class);
            if(workFlowDefinitionOption.allowRevoke){
                continue;
            }
            throw new IllegalArgumentException("流程定义["+workFlowDefinition.getName()+"]不允许撤销操作");
        }
    }

    private void transactionUpdate(FlowContext flowContext){
        DAO dao = flowContext.checkInstanceData(DAO.class);
        dao.startTransaction(transaction -> {
            flowContext.putInstanceData(transaction, Transaction.class);
            updateInstanceStatus(flowContext);
            deleteInstanceTask(flowContext);
            addWorkFlowHistoryFlow(flowContext);
        });
    }

    private void updateInstanceStatus(FlowContext flowContext){
        Transaction transaction = flowContext.checkInstanceData(Transaction.class);
        List<Long> workFlowInstanceIdList = flowContext.checkData("workFlowInstanceIdList", List.class);

        transaction.addRecordString("更新工作流实例状态为撤回");
        transaction.query(WorkFlowInstance.class)
                .addInQuery("id", workFlowInstanceIdList)
                .addUpdate("status", WorkFlowInstanceStatus.Revoke.status)
                .execute()
                .update();
    }

    private void deleteInstanceTask(FlowContext flowContext){
        Transaction transaction = flowContext.checkInstanceData(Transaction.class);
        List<Long> workFlowInstanceIdList = flowContext.checkData("workFlowInstanceIdList", List.class);

        transaction.addRecordString("删除所有未完成的任务");
        //删除所有未完成任务
        transaction.query(WorkFlowTask.class)
                .addInQuery("instanceId", workFlowInstanceIdList)
                .addQuery("complete", false)
                .execute()
                .delete();
    }

    private void addWorkFlowHistoryFlow(FlowContext flowContext){
        List<WorkFlowInstance> workFlowInstanceList = flowContext.checkData("workFlowInstanceList", List.class);
        for(WorkFlowInstance workFlowInstance:workFlowInstanceList){
            flowContext.putInstanceData(workFlowInstance);
            flowContext.startFlow(new AddWorkFlowHistoryFlow())
                    .putCurrentCompositeFlowData("message", "撤回申请")
                    .execute();
            flowContext.startFlow(new AddWorkFlowHistoryFlow())
                    .putCurrentCompositeFlowData("message", "工作流实例已结束")
                    .execute();
        }
    }
}
